package com.ledou44.ledourpc.configuration;

import com.ledou44.ledourpc.ServiceBeanFactory;
import com.ledou44.ledourpc.annotation.LedouService;
import com.ledou44.ledourpc.annotation.Reference;
import com.ledou44.ledourpc.client.Client;
import com.ledou44.ledourpc.utils.CreateProxyBeanUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

@Component
public class LedouRpcBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 在目标对象实例化之后调用，这个时候对象已经被实例化，但是该实例的属性还未被设置，都是null，对象还未生成。
     * 因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素
     * （因为还有一个因素是mbd.getDependencyCheck()）；如果该方法返回false,并且不需要check，
     * 那么postProcessPropertyValues就会被忽略不执行；如果返回true，postProcessPropertyValues就会被执行
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        //该方法面向服务消费者，对Reference注解增强
        Field[] fields = bean.getClass().getDeclaredFields();
        for(Field field : fields) {
            Reference reference = field.getAnnotation(Reference.class);
            if(reference != null) {
                field.setAccessible(true);
                Class<?> type = field.getType();
                try {
                    Client client = applicationContext.getBean(Client.class);
                    //CreateProxyBeanUtil.createReferenceBean方法会调用CGLib的动态代理，并返回代理对象放入field属性替代原对象
                    field.set(bean, CreateProxyBeanUtil.createReferenceBean(type, client));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * BeanPostProcessor接口中的方法
     * 在Bean的自定义初始化方法执行完成之后执行(对象已经生成)
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        LedouService ledouService = bean.getClass().getAnnotation(LedouService.class);
        if(ledouService != null) {
            Class<?>[] interfaces = bean.getClass().getInterfaces();
            for(Class<?> inter : interfaces) {
                String key = inter.getName();
                //将该类的所有接口和它自己建立起一个映射
                ServiceBeanFactory.beanFactory.put(key,bean);
            }
        }
        return bean;
    }
}
